package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import exception.GameException;

abstract public class Table
{
	protected int seats;
	
	protected CardStack cardStack;
	
	protected Game game;
	
	protected GameRound currentGameRound;
	
	protected GameRoundState gameRoundState;
	
	protected ArrayList<Participant> participants = new ArrayList<Participant>();
	
	protected ArrayList<SidePot> sidePots = new ArrayList<SidePot>();
	
	protected MainPot mainPot = new MainPot();
	
	protected int currentPot = -1;
	
	protected final Board board;

	protected int currentEndPosition;

	public final static Comparator<Participant> participantSeatSorter = new Comparator<Participant>()
	{
		public int compare(Participant p1, Participant p2)
		{
			// 1 = down, -1 = up
			return p1.getSeatIndex() >= p2.getSeatIndex() ? 1 : -1;
		}
	};
	
	public Table(int seats)
	{
		this.seats = seats;
		
		setCurrentEndPosition(seats);
		
		board = new Board();
	}
	
	abstract protected void refillCardStack();
	
	public void clear()
	{
		cardStack.clear();
		
		refillCardStack();
		
		cardStack.shuffle();
		
		board.clear();
		
		for (Participant participant: participants)
		{
			participant.getHand().clear();
		}
	}

	public MainPot getMainPot()
	{
		return mainPot;
	}
	
	public int getMainPotChips()
	{
		return mainPot.getChips();
	}
	
	public void addSidePot()
	{
		sidePots.add(new SidePot());
	}

	public ArrayList<SidePot> getSidePots()
	{
		return sidePots;
	}
	
	public Pot getCurrentPot()
	{
		if (currentPot == 0)
		{
			return mainPot;
		}
		else
		{
			return sidePots.get(currentPot - 1);
		}
	}
	
	public int getCurrentPotIndex()
	{
		return currentPot;
	}
	
	public void nextPot()
	{
		currentPot++;
		
		if (currentPot > 0)
		{
			addSidePot();
		}
	}
	
	public Pot getNextPot()
	{
		nextPot();
		
		return getCurrentPot();
	}
	
	public void emptyPots()
	{
		mainPot.empty();
		
		sidePots.clear();
		
		currentPot = -1;
	}
	
	public int getSeats()
	{
		return seats;
	}
	
	public void setCardStack(CardStack cardStack)
	{
		this.cardStack = cardStack;
	}
	
	public CardStack getCardStack()
	{
		return cardStack;
	}
	
	public void setGame(Game game)
	{
		this.game = game;
	}
	
	public Game getGame()
	{
		return game;
	}
	
	public int getGameId()
	{
		return getGame().getId();
	}

	public void setCurrentGameRound(GameRound gameRound)
	{
		this.currentGameRound = gameRound;
	}
	
	public GameRound getCurrentGameRound()
	{
		return currentGameRound;
	}
	
	public void setGameRoundState(GameRoundState gameRoundState)
	{
		this.gameRoundState = gameRoundState;
	}
	
	public GameRoundState getGameRoundState()
	{
		return gameRoundState;
	}
	
	public Board getBoard()
	{
		return board;
	}
	
	public void takeSeat(Participant participant, int seatIndex) throws GameException
	{
		if (checkSeatsTaken())
		{
			for (Participant p: participants)
			{
				if (p.getSeatIndex() == seatIndex)
				{
					throw new GameException("This seat is already taken.");
				}
			}
			
			participant.setSeatIndex(seatIndex);
			
			participants.add(participant);
		}
	}
	
	public void leave(Participant participant)
	{
		participants.remove(participant);
	}
	
	public ArrayList<Participant> getParticipants()
	{
		return participants;
	}
	
	public boolean checkSeatsTaken()
	{
		return participants.size() < seats;
	}
	
	public boolean checkSeatsTaken(boolean throwException) throws GameException
	{
		boolean seatsNotTaken = checkSeatsTaken();
		
		if (!seatsNotTaken && throwException)
		{
			throw new GameException("All seats have been taken.");
		}
		
		return seatsNotTaken;
	}
	
	abstract void startBody() throws GameException;
	
	public void start() throws GameException
	{
		Collections.sort(participants, participantSeatSorter);
		
		// Fix: make shift positions work right, because the first time they should not shift.
		participants.add(participants.remove(0));
		
		startBody();
		
		getGame().payout();
	}
	
	public void shiftPositions()
	{
		// Replace the last element to the front, so all elements shift one
		// place to the right.
		participants.add(0, participants.remove(participants.size() - 1));
		
		int position = 0;
		
		for (Participant participant: participants)
		{
			// Were starting at position 1, so we need to pre increment.
			participant.setPosition(++position);
		}
	}
	
	public void setCurrentEndPosition(int currentEndPosition)
	{
		this.currentEndPosition = currentEndPosition;
	}
	
	public int getCurrentEndPosition()
	{
		return currentEndPosition;
	}
}
